iT邦幫忙

2022 iThome 鐵人賽

DAY 22
0

GoF 對備忘錄模式(Memento)的定義是:
「在不違反封裝的原則下,取得一個物件的內部狀態並保留在外部,讓該物件可以在日後恢復到原先保留的狀態。」

以存檔機制來說的話,就是希望有個可以將存檔的資料儲存起來的方式,並在需要的時候從存檔資料讀進遊戲裡設定,下面會先舉例一般例子的範例。

Memento.cs

namespace LinXuan.DesignPattern.Example.Memento
{ 
    public class Memento 
    { 
        string m_SaveData; 

        public string GetSaveData() 
        { 
            return m_SaveData; 
        } 

        public void SetSaveData(string saveData) 
        { 
            m_SaveData = saveData; 
        } 
    } 
}

Originator.cs

using UnityEngine; 

namespace LinXuan.DesignPattern.Example.Memento 
{ 
    public class Originator 
    { 
        string m_SaveData; 
        public void SetInfo(string saveData) 
        { 
            m_SaveData = saveData; 
        } 

        public void ShowInfo() 
        { 
            Debug.Log("Originator State:" + m_SaveData); 
        } 

        public Memento CreateMemento() 
        { 
            Memento newMemento = new Memento(); 
            newMemento.SetSaveData(m_SaveData); 
            return newMemento; 
        } 

        public void SetMemento(Memento memento) 
        { 
            m_SaveData = memento.GetSaveData(); 
        } 
    } 
}

MementoTest.cs

using UnityEngine; 

namespace LinXuan.DesignPattern.Example.Memento
{ 
    public class MementoTest : MonoBehaviour 
    { 
        private Originator m_Originator = new Originator(); 
        void Start() 
        { 
            m_Originator.SetInfo("Step1"); 
            m_Originator.ShowInfo(); 
            Memento memento = m_Originator.CreateMemento(); 
            m_Originator.SetInfo("Step2"); 
            m_Originator.ShowInfo(); 
            m_Originator.SetMemento(memento); 
            m_Originator.ShowInfo(); 
        } 
    } 
}

輸出如下
https://ithelp.ithome.com.tw/upload/images/20221005/20151894CjUGW46A42.png

實際範例

流離之歌這款遊戲用來製作存檔機制的程式主要會用Easy Save 3,如果沒有的話可以用Unity內建的PlayerPrefs製作類似的功能
不過這邊的程式碼其實寫的不算太好,有機會的話是想要在優化一下就是...

CALSaveSystem.cs

using LuLuBearStudio.Save; 
using System.Collections.Generic; 
using UnityEngine; 

public class CALSaveSystem : MonoBehaviour 
{ 
    [SerializeField] private bool m_IsTest = false; 
    [SerializeField] private SaveDataSO m_SaveDataSO;//用ScriptableObject製作的暫時存檔,
    [SerializeField] private int m_InitinalScene = 1; 
    private int defaultResolutionIndex; 
    public bool CurrentSceneDialogueIsComplete { set => m_SaveDataSO.CurrentSceneDialogueIsComplete = value; get => m_SaveDataSO.CurrentSceneDialogueIsComplete; } 
    public bool IsBattleScene { set => m_SaveDataSO.IsBattleScene = value; get => m_SaveDataSO.IsBattleScene; } 
    public int EndSceneNumber => m_SaveDataSO.EndSceneNumber; 
    public int InitinalSceneNumber => m_SaveDataSO.InitinalSceneNumber; 
    public SaveDataSO SaveDataSO => m_SaveDataSO; 

    public void SaveCurrentScene(int sceneNumber) 
    { 
        m_SaveDataSO.SceneNumber = sceneNumber; 
        if(!m_IsTest) 
            ES3.Save("mySaveData", m_SaveDataSO.SceneNumber); //ES3.Save的存檔到電腦資料夾的部分
    } 

    public void SaveResData() 
    { 
        if(!m_IsTest) 
            ES3.Save("userResItem", m_SaveDataSO.UserResItem); 
    } 

    public void SaveAudioSaveData() 
    { 
        if(!m_IsTest) 
            ES3.Save("audioVolSaveData", m_SaveDataSO.AudioVolSaveData); 
    } 

    public int LoadSceneNumber() 
    { 
        return m_SaveDataSO.SceneNumber; 
    } 

    public void LoadAllSaveData() 
    { 
        LoadSceneSaveData(); 
        LoadAudioSaveData(); 
        LoadResItemSaveData(); 
    } 

    public void LoadSceneSaveData() 
    { 
        if (ES3.KeyExists("mySaveData") && !m_IsTest) //如果ES3可以從電腦存檔的資料夾讀取到資料,就會把資料讀取出來儲存在SaveDataSO裡
        { 
            m_SaveDataSO.SceneNumber = ES3.Load<int>("mySaveData"); 
        } 
    } 

    public void LoadAudioSaveData() 
    { 
        if(ES3.KeyExists("audioVolSaveData") && !m_IsTest) 
        { 
            m_SaveDataSO.AudioVolSaveData = ES3.Load<AudioVolSaveData>("audioVolSaveData"); 
        } 
    } 

    public void LoadResItemSaveData() 
    { 
        if (ES3.KeyExists("userResItem") && !m_IsTest) 
        { 
            m_SaveDataSO.UserResItem = ES3.Load<ResItem>("userResItem"); 
        } 
        else 
        { 
            ResolutionInitinal(); 
        } 
    } 

    public void RestartGame() 
    { 
        m_SaveDataSO.SceneNumber = m_InitinalScene; 
        if(!m_IsTest) 
            ES3.Save("mySaveData", m_SaveDataSO.SceneNumber); 
    } 

    private void ResolutionInitinal() 
    { 
        //Resolution initinalize...
    } 
}

參考資料

設計模式與遊戲開發的完美結合(暢銷回饋版)
Turn Based Strategy Framework
流離之歌


上一篇
Day 21:Adapter模式與外接對話框插件
下一篇
Day 23:Visitor模式(一)
系列文
如何在Unity裡寫出具有一定擴充性的遊戲30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言